'''
Created on 30-Jul-2010

@author: dexen
'''

FREECADPATH = '/usr/lib/freecad/lib'
import sys
sys.path.append(FREECADPATH)

import os
import math
import random

import FreeCAD
import daysimfunc
import anticlockwise
import fold
from FreeCAD import Part
from FreeCAD import Base
from draftlibs import fcgeo
from draftlibs import fcvec
from pybim import Building, Roof, Shade, Wall, Window, Zone, Floor


#THE CLASS WAS WRITTEN ASSUMING ALL THE POINTS ARE COMING IN ANTI-CLOCKWISE ARRANGEMENT WITH NORMAL POINTING OUTWARDS

ROOT = "/home/dexen/workspace/overhang_schema"


def face_vertexes_normals(faces):
    face_list = []
    normal_list = []
    sort_edge_list = []
    for face in faces :
        if face:
            face_list.append([])
            normal_x =  face.normalAt(0,0).x
            normal_y =  face.normalAt(0,0).y
            normal_z =  face.normalAt(0,0).z
            normal = (normal_x,normal_y,normal_z)
            normal_list.append(normal)
            edges = face.Edges
            sort_edges = Part.__sortEdges__(edges)
            sort_edge_list.append(sort_edges)
            #sort thru all the edges and identify the common vertex
            round_var = 6
            for counter in range(len(sort_edges)):
                edge_pnts = []
                if counter < len(sort_edges)-1:
                    length = sort_edges[counter].Length
                    length2 = sort_edges[counter+1].Length
                    pnt_start1 = (round(sort_edges[counter].valueAt(0).x,round_var ),round(sort_edges[counter].valueAt(0).y, round_var), 
                                  round(sort_edges[counter].valueAt(0).z,round_var))
                    
                    pnt_end1 = (round(sort_edges[counter].valueAt(length).x, round_var), round(sort_edges[counter].valueAt(length).y, round_var), 
                                round(sort_edges[counter].valueAt(length).z,round_var))
                    
                    pnt_start2 = (round(sort_edges[counter+1].valueAt(0).x,round_var), round(sort_edges[counter+1].valueAt(0).y, round_var), 
                                  round(sort_edges[counter+1].valueAt(0).z, round_var))
                    
                    pnt_end2 = (round(sort_edges[counter+1].valueAt(length2).x, round_var), round(sort_edges[counter+1].valueAt(length2).y, round_var), 
                                round(sort_edges[counter+1].valueAt(length2).z, round_var))
                    
                    edge_pnts.append(pnt_start1)
                    edge_pnts.append(pnt_end1)
                    edge_pnts.append(pnt_start2)
                    edge_pnts.append(pnt_end2)
                    
                else:
                    length = sort_edges[counter].Length
                    length2 = sort_edges[0].Length
                    pnt_start1 = (round(sort_edges[counter].valueAt(0).x, round_var),round(sort_edges[counter].valueAt(0).y, round_var), 
                                  round(sort_edges[counter].valueAt(0).z, round_var))
                    
                    pnt_end1 = (round(sort_edges[counter].valueAt(length).x, round_var), round(sort_edges[counter].valueAt(length).y, round_var), 
                                round(sort_edges[counter].valueAt(length).z, round_var))
                    
                    pnt_start2 = (round(sort_edges[0].valueAt(0).x, round_var), round(sort_edges[0].valueAt(0).y, round_var), 
                                  round(sort_edges[0].valueAt(0).z, round_var))
                    
                    pnt_end2 = (round(sort_edges[0].valueAt(length2).x, round_var), round(sort_edges[0].valueAt(length2).y, round_var), 
                                round(sort_edges[0].valueAt(length2).z, round_var))
                    
                    edge_pnts.append(pnt_start1)
                    edge_pnts.append(pnt_end1)
                    edge_pnts.append(pnt_start2)
                    edge_pnts.append(pnt_end2)
            
                counterx =0
                for edge_pnt in edge_pnts:
                    for num_pnt in range(len(edge_pnts)):
                        if num_pnt <= len(edge_pnts) - (2+counterx):
                            if edge_pnt == edge_pnts[num_pnt + (1+counterx)]:
                                face_list[-1].append(edge_pnt)
                    counterx +=1
        else:
            face_list.append(None)
            normal_list.append(None)
            sort_edge_list.append(None)
            
    return face_list, normal_list, sort_edge_list 

def arrange_vertexes_anticlockwise(face_points, normal):
    anticlockwise_facelist = []
    counter = 0
    for point in face_points:
        if point:
            anticlockwise_facelist.append(anticlockwise.anticlockwise(point, normal[counter]))
        else:
            anticlockwise_facelist.append(None)
        counter +=1
        
    return anticlockwise_facelist

def intersection_edges(edge_list):    
    intersection_list = []
    counter = 0
    for edge in edge_list:
        if counter < len(edge_list)-1:
            intersection_pt = fcgeo.findIntersection(edge, edge_list[counter + 1], infinite1 = True, infinite2 = True)
            intersection_list.append(intersection_pt)
        if counter == len(edge_list)-1:
            intersection_pt = fcgeo.findIntersection(edge, edge_list[0], infinite1 = True, infinite2 = True)
            intersection_list.append(intersection_pt)
        counter +=1

    return intersection_list
        
        
def generate_freecad(variables):
    import Part
    #EXTRACT THE DIFFERENT VARIABLES
    area = 225
    building_length = variables[0]
    building_width = area/building_length
    height = variables[1]
    rotation = variables[2]
    slope = variables[13]*height
    num_walls = 4
    
    material_dict = {"sglclr": 0,
                     "dblclr": 0,
                     "lightwall": 0,
                     "heavywall": 0,
                     "lightrf": 0,
                     "heavyrf": 0,
                     "shade": 0,
                     "floor": 0}
    
    #MAKE A BOX USING THE PART MOD
    building = Part.makeBox(building_length,building_width,height)
    #GET THE FLOOR AND THE ROOF OF THE BOX 
    top_face = building.Faces[5]
    bottom_face = building.Faces[4]
    
    #FIND THE EDGE AND MOVE IT UP TO CREATE THE ROOF SLOPE
    top_edge = top_face.Edges[1]
    move_vector = (0,0,slope)
    edge_trsf = Base.Matrix()
    edge_trsf.move(Base.Vector(move_vector))
    move_top_edge = top_edge.transformGeometry(edge_trsf)
    #MOVE IT DOWN THE ROOF AND LOFT IT TO CREATE A SURFACE FOR THE ROOF 
    edge_trsf2 = Base.Matrix()
    #FIND THE DISTANCE BETWEEN THE EDGES ON THE ROOF FOR THE LOFTING 
    move_vector2 = fcgeo.findMidpoint(top_face.Edges[3]).sub(fcgeo.findMidpoint(top_edge))
    edge_trsf2.move(move_vector2)
    move_top_edge2 = top_edge.transformGeometry(edge_trsf2)
    #THE FIRST ONE FOR REFERENCE 
    roof = Part.makeLoft([Part.Wire(move_top_edge),Part.Wire(move_top_edge2)])
    #SECOND ONE IS THE REAL INFORMATION 
    rroof = Part.makeLoft([Part.Wire(move_top_edge),Part.Wire(move_top_edge2)])
    
    #MOVE THE TOP EDGE DOWN TO THE FLOOR AS A REFERENCE FOR CREATIGN THE FLOOR SURFACE
    move_vector3 = (0,0,-height)
    edge_trsf3 = Base.Matrix()
    edge_trsf3.move(Base.Vector(move_vector3))
    move_bottom_edge = top_edge.transformGeometry(edge_trsf3)
    #MOVE THE EDGE ACROSS THE FLOOR SURFACE FOR THE LOFTING ACTION 
    move_vector4 = fcgeo.findMidpoint(bottom_face.Edges[3]).sub(fcgeo.findMidpoint(top_edge))
    edge_trsf4 = Base.Matrix()
    edge_trsf4.move(Base.Vector(move_vector4))
    move_bottom_edge2 = top_edge.transformGeometry(edge_trsf4)
    #THE FIRST ONE FOR REFERENCE 
    floor = Part.makeLoft([Part.Wire(move_bottom_edge),Part.Wire(move_bottom_edge2)])
    #SECOND ONE IS THE REAL INFORMATION 
    rfloor = Part.makeLoft([Part.Wire(move_bottom_edge),Part.Wire(move_bottom_edge2)])
    
    #LOFT BOTH THE FLOOR AND THE ROOF TO CREATE THE 4 WALLS
    #THE FIRST ONE FOR REFERENCE 
    walls = Part.makeLoft([roof.Wires[0], floor.Wires[0]])
    #SECOND ONE IS THE REAL INFORMATION 
    rwalls = Part.makeLoft([rroof.Wires[0], rfloor.Wires[0]])
    
    #PUT ALL THE FACES INTO 1 LIST 
    #THE FIRST ONE FOR REFERENCE 
    faces = walls.Faces
    #REVERSE THE SURFACE TO MAKE THE NORMAL POINT OUTWARDS
    for aface in faces:
        aface.reverse()
    #REVERSE THE FLOOR SURFACE TO HAVE IT POINT DOWNWARDS
    rev_flr = floor.Faces[0]
    #rev_flr.reverse()
    faces.append(rev_flr)
    rev_roof = roof.Faces[0]
    rev_roof.reverse()
    faces.append(rev_roof)
    
    #SECOND ONE IS THE REAL INFORMATION 
    rfaces = rwalls.Faces
    #for arface in rfaces:
        #arface.reverse()
    #REVERSE THE SURFACE TO MAKE THE NORMAL POINT OUTWARDS
    rev_rflr = rfloor.Faces[0]
    #rev_rflr.reverse()
    rfaces.append(rev_rflr)
    rev_rroof = rroof.Faces[0]
    rev_rroof.reverse()
    rfaces.append(rev_rroof)
    for rface in rfaces:
        rface.rotate((0, 0, 0), (0, 0, 1), rotation)
        rface.reverse()
    #AREA OF THE SURFACES    
    flr_area = rfaces[4].Area
    material_dict["floor"] =  material_dict["floor"] + flr_area
    
    if variables[11] == 0:
        rf_area = rfaces[5].Area
        material_dict["lightrf"] =  material_dict["lightrf"] + rf_area
    if variables[11] == 1:
        rf_area = rfaces[5].Area
        material_dict["heavyrf"] =  material_dict["heavyrf"] + rf_area
        
    rwall_face_info = face_vertexes_normals(rfaces)
    #loop thru all the face and arrange all of them in anti-clockwise direction 
    rwall_face_points = rwall_face_info[0]
    rwall_normal_list = rwall_face_info[1]    
    
    rwall_anticlockwise_facelist = arrange_vertexes_anticlockwise(rwall_face_points, rwall_normal_list)
    
    #FOR REFERENCE PURPOSES IN CREATING THE WINDOW AND THE SHADES
    #count thru the faces and sort the edges in continuous manner and get all the points
    wall_face_info = face_vertexes_normals(faces)
    #loop thru all the face and arrange all of them in anti-clockwise direction 
    wall_face_points = wall_face_info[0]
    
    wall_normal_list = wall_face_info[1]
    
    #this will turn the order of the vertexes into anti clockwise manner
    wall_anticlockwise_facelist = arrange_vertexes_anticlockwise(wall_face_points, wall_normal_list)
    
    #construct the windows    
    window_list = []
    offset_edge_list = []

    
    #DRAW A POLYGON USING THE WALL INFORMATION AND OFFSET THE WALL INWARDS TO CREATE A WINDOW 
    for wall in range(num_walls):
        wall_mat = variables[wall + 3]
        if wall_mat == 0 or wall_mat == 1 :
            vector_list =[]
            #GET THE VECTORS FROM THE REFERENCE WALLS IN ORDER TO DRAW THE POLYGON 
            for apnt in wall_anticlockwise_facelist[wall]:
                vector_pnt = Base.Vector(apnt[0], apnt[1], apnt[2])
                vector_list.append(vector_pnt)
                
            #make a polygon of the face
            vector_list.append(vector_list[0])
            polygon = Part.makePolygon(vector_list)
            offset_polygon = fold.offsetWire(polygon,0.5)
            window_face = Part.Face(offset_polygon)
            window_list.append(window_face)
            if wall_mat == 0:
                sglclr_area = window_face.Area
                frame_area = rfaces[wall].Area - sglclr_area
                material_dict["sglclr"] = material_dict["sglclr"] + sglclr_area
                material_dict["lightwall"] = material_dict["lightwall"] + frame_area
            if wall_mat == 1:
                dblclr_area = window_face.Area
                frame_area = rfaces[wall].Area - dblclr_area
                material_dict["dblclr"] = material_dict["dblclr"] + dblclr_area
                material_dict["lightwall"] = material_dict["lightwall"] + frame_area
        else:
            window_list.append(None)
            if wall_mat == 2:
                light_area = rfaces[wall].Area
                material_dict["lightwall"] = material_dict["lightwall"] + light_area
                
            if wall_mat == 3:
                heavy_area = rfaces[wall].Area
                material_dict["heavywall"] = material_dict["heavywall"] + heavy_area
                

    #ROTATE THE WINDOW 
    for awin in window_list:
        if awin:
            awin.rotate((0, 0, 0), (0, 0, 1), rotation)
            awin.reverse()
    win_face_info = face_vertexes_normals(window_list)
    win_face_points = win_face_info[0]
    win_normal_list = win_face_info[1]    
    
    win_anticlockwise_facelist = arrange_vertexes_anticlockwise(win_face_points, win_normal_list)
    
    
    #CONSTRUCT THE SHADING 
    #get the roof surface
    rf_vector_list = []
    #GET THE VECTORS FROM THE REFERENCE ROOF IN ORDER TO DRAW THE POLYGON 
    for rfpnt in wall_anticlockwise_facelist[5]:
        rf_vector_pnt = Base.Vector(rfpnt[0], rfpnt[1], rfpnt[2])
        rf_vector_list.append(rf_vector_pnt)
        
    #REARRANGED THE VERTEXES SO THAT IT COINCIDE WITH THE ORDER OF THE WALLS
    rearranged_rf_vector_list = [rf_vector_list[3], rf_vector_list[0], rf_vector_list[1], rf_vector_list[2], rf_vector_list[3]] 
  
    rf_polygon = Part.makePolygon(rearranged_rf_vector_list)
    
    #construct the shading
    shade_edge_list = []
    for wall in range(num_walls):
        shade_depth = variables[wall + 7]
    #CONSTRUCTING THE SHADING BY OFFSETING THE ROOF AND OBTAINING THAT PARTICULAR EDGE FOR EACH SHADING 
        offset_rf_polygon = fold.offsetWire(rf_polygon,-shade_depth)
        shade_edge_list.append(offset_rf_polygon.Edges[wall])
     
    #INTERSECT THE 4 EDEGE TO GET 4 VERTEXES     
    inter_pts = intersection_edges(shade_edge_list)
    
    #REARRANGE SO THAT WHEN YOU DRAW THE POLYGON THE EDGE WILL COINCIDE WITH THE ORDER OF THE WALL 
    rearranged_inter_pts = [inter_pts[3][0], inter_pts[0][0], inter_pts[1][0], inter_pts[2][0], inter_pts[3][0]]
    #DRAW THE POLYGON AND LOFT IT TO CREATE THE SHADES
    shade_poly = Part.makePolygon(rearranged_inter_pts)
    shade_list =Part.makeLoft([shade_poly,rf_polygon])
    shade_list = shade_list.Faces
    
    #CLEAN THE LIST OF EMPTY SHADE SURFACES AS THE LOFT ACTION AUTOMATICALLY CREATES SURFACE EVEN IF THERE IS NONE 
    for wall in range(num_walls):
        shade_depth = variables[wall + 7]
        if shade_depth == 0:
            del shade_list[wall]
            shade_list.insert(wall,None)
            
    #ROTATE THE SHADE SURFACES 
    for ashade in shade_list:
        if ashade:
            ashade.rotate((0, 0, 0), (0, 0, 1), rotation)
            shade_area = ashade.Area
            material_dict["shade"] = material_dict["shade"] + shade_area
            
    #PROCESS THE FACES AND OUTPUT THE NECCESSARY VERTEXES AND POINTS 
    shade_face_info = face_vertexes_normals(shade_list)
    shade_face_points = shade_face_info[0]
    shade_normal_list = shade_face_info[1] 
    
    shade_anticlockwise_facelist = arrange_vertexes_anticlockwise(shade_face_points, shade_normal_list)
    
    #GET THE SENSOR POINTS
    sensor_list = []
    flr_sensor = rfaces[4]
    uv = flr_sensor.ParameterRange
    u_range = (uv[1]-uv[0])/6
    v_range = (uv[3]-uv[2])/6 
    for u_sensor in range(1,6,2):
        for v_sensor in range(1,6,2):
            sensor_pt = flr_sensor.valueAt(uv[0] + (u_sensor*u_range), uv[2] + (v_sensor*v_range))
            sensor_pt_h = sensor_pt.add(Base.Vector(0,0,0.85))
            sensor_pt_tup = fcvec.tup(sensor_pt_h)
            sensor_list.append(sensor_pt_tup)
    
    return rwall_anticlockwise_facelist, win_anticlockwise_facelist, shade_anticlockwise_facelist, sensor_list, material_dict

def make_geometry(variables, building):
    #CREATE THE BUILDING AND ZONE OBJECT
    zone1 = Zone("zone1", building)
    #FLOOR CLASS 
    building.add_variables(variables)
    floor_list = generate_freecad(variables)[0][4]
    if variables[12] == 0:
        floor = Floor("FLOOR", floor_list, "Ground")
        floor.material_idf("Heavy Floor")
        floor.material_rad("floor_mat")
        zone1.add_floor(floor)
    else:
        floor = Floor("FLOOR", floor_list, "Outdoors")
        floor.material_idf("Heavy Floor")
        floor.material_rad("floor_mat")
        zone1.add_floor(floor)
    
    roof_list = generate_freecad(variables)[0][5]
    #ROOF CLASS
    if variables[11] == 0:
        roof = Roof("ROOF", roof_list)
        roof.material_idf("Light Roof/Ceiling")
        roof.material_rad("ceiling_mat")
        zone1.add_roof(roof)
    else:
        roof = Roof("ROOF", roof_list)
        roof.material_idf("Heavy Roof/Ceiling")
        roof.material_rad("ceiling_mat")
        zone1.add_roof(roof)
        
    num_wall = 4
    wall_list = generate_freecad(variables)[0][0:4]
    wall_names = ["WALL1", "WALL2", "WALL3", "WALL4"]
    #GET THE WINDOWS POINTS
    for counter in range(num_wall):
        #WALL CLASS
        wall_mat = variables[counter + 3]
        if wall_mat == 0 or wall_mat == 1:
            wall = Wall(wall_names[counter], wall_list[counter])
            wall.material_idf("Medium Exterior Wall")
            wall.material_rad("wall_mat")
            zone1.add_wall(wall)
            
        if wall_mat == 2:
            wall = Wall(wall_names[counter], wall_list[counter])
            wall.material_idf("Light Exterior Wall")
            wall.material_rad("wall_mat")
            zone1.add_wall(wall)
            
        if wall_mat == 3:
            wall = Wall(wall_names[counter], wall_list[counter])
            wall.material_idf("Heavy Exterior Wall")
            wall.material_rad("wall_mat")
            zone1.add_wall(wall)
            
        window_list = generate_freecad(variables)[1]
        win_names = ["WINDOW1", "WINDOW2",  "WINDOW3",  "WINDOW4"]
        if window_list[counter]:
            if wall_mat == 0:
                window = Window(win_names[counter], window_list[counter])
                window.material_idf("Sgl Clr 6mm")
                window.material_rad("window_glass")
                wall.add_window(window)
            
            if wall_mat == 1:
                window = Window(win_names[counter], window_list[counter])
                window.material_idf("Dbl Clr 6mm/6mm Air")
                window.material_rad("window_glass2")
                wall.add_window(window)
        
        shade_list = generate_freecad(variables)[2]
       
        shading_names  = ["SHADING1", "SHADING2",  "SHADING3",  "SHADING4"]
        if shade_list[counter]:
            shade = Shade(shading_names[counter], shade_list[counter])
            shade.material_rad("shading_mat")
            wall.add_shade(shade)
            
    #SENSOR POINTS
    sensor_pts = generate_freecad(variables)[3]
    zone1.add_sensor_pts(sensor_pts)
    
    #CALCULATE THE COST 
    material_dict = generate_freecad(variables)[4]
    #COST OF MATERIAL 
    #LIGHTWALL,FLOOR, LIGHTROOF, SHADE  = 1
    cost1 = (material_dict["lightwall"] + material_dict["lightrf"] + material_dict["floor"] + material_dict["shade"]) * 1 
    #HEAVYWALL,HEAVYROOF = 1.5
    cost2 = (material_dict["heavywall"] + material_dict["heavyrf"]) * 1.5 
    #SGLCLR = 2
    cost3 = (material_dict["sglclr"]) *2
    #DBLCLR = 2.5
    cost4 = material_dict["dblclr"] *2.5
    total_cost = cost1 + cost2 + cost3 + cost4
    building.costfactor.append(total_cost)
    
    #OUTPUT A DXF FILE 
    path = ROOT + "/result.dxf"
    building.dxf(path)

#--------------------------------------------------------------------------------
#function for generating random height and width
def gmap(gene, values):
    step = 1.0 / len(values)
    for i in range(len(values)):
        if gene < (step + i*step):
            return values[i]
            
#--------------------------------------------------------------------------------
def generate_rad_file(variables, building):
    rad_data = []
    
    #WRITING THE RADIANCE FILE 
    #get the base file of the idf 
    #base_rad_file = os.path.join(ROOT,'radiancebasefile/overhangschema.rad')    

    #read all the stuff in the base idf file 
    #base_rad_file = open(base_rad_file,  "r")
    #base_rad_stuff = base_rad_file.read()
    #base_rad_file.close()

    #write the base file 
    #rad_data.append(base_rad_stuff)
    rad_geometry_data = building.rad(interior = True)
    rad_data.append(rad_geometry_data)
    direction = "0 0 1"
    rad_sensor_data = building.sensor_pts(direction)
    return rad_data, rad_sensor_data

def execute_radiance(rad_file_path, sensor_file_path):
    oconv_file = ROOT + "/radiancebasefile/rad_out/rad_results.oconv"
    sensors_file = sensor_file_path
    file = ROOT + "/radiancebasefile/rad_out/rad_results.txt"
    
    #create oconv file
    command1 = "oconv " + "'" + ROOT + "/radiancebasefile/overhangschema_mat.rad" + "'" + " "\
    + "'" + ROOT + "/radiancebasefile/overhangschema_sky.rad" + "'" + " " + "'" + rad_file_path + "'"\
    + " " + ">" + " " + "'" + oconv_file + "'"
    os.system(command1)
    
    #execute rtrace 
    command2 = "rtrace -h -w -I+ -ab 3 " + "'" +  oconv_file + "'" + " " + " < " + " " + "'" + sensors_file + "'"\
    + " " + " > " + " " + "'" + file + "'" 
    os.system(command2)
    
#--------------------------------------------------------------------------------  
def generate_idf_file(variables, building):
             
    idf_data = []
    
    #WRITING THE ENERGYPLUS FILE 
    #get the base file of the idf 
    base_idf_file = os.path.join( ROOT,'energyplusbasefile/overhangschema.idf')
    #read all the stuff in the base idf file 
    base_idf_file = open(base_idf_file,  "r")
    base_stuff = base_idf_file.read()
    base_idf_file.close()

    #write the base_stuff 
    idf_data.append(base_stuff)
    for _ in range(10):
        idf_data.append("! ======================================== \n")
        
    geometry_data = building.idf()
    idf_data.append(geometry_data)
    return idf_data
    
def execute_energyplus(idf_data,  path,  filename):
    
    idf_file_path = path + filename + ".idf"
    if not os.path.isdir(path):
        os.mkdir(path)
    idf_file = open(idf_file_path,  "w")
    for data in idf_data:
        idf_file.write(data)
    idf_file.close()
    
    #run energyplus simulation for each file 
    command = "runenergyplus '" +  idf_file_path + "' 'SGP_Singapore.486980_IWEC.epw'"
    os.system(command)
    
#--------------------------------------------------------------------------------
def generate_hea_file(path, filename, rad_file_path, sensor_file_path):
    
    #WRITING THE DAYSIM FILE 
    #get the base file of the hea
    base_hea_file = os.path.join(ROOT, 'daysimbasefile/overhangschema.hea')

    #read all the stuff in the base hea file 
    base_hea_file = open(base_hea_file,  "r")
    base_stuff = base_hea_file.read()
    base_hea_file.close()
    hea_data = []
    #create a foler to store daysim results / input the path as accordingly
    hea_data.append(base_stuff)
           
    #WRITE THE PROJ_INFO
    hea_file_path = path 
    tmp_dir = hea_file_path  + "tmp/"
    proj_info = daysimfunc.write_proj_info(filename, hea_file_path, tmp_dir)
    hea_data.append(proj_info)
    
    #WRITE THE WEATHER DATA 
    wea_file_dir = '/home/dexen/daysim/wea/SGP_Singapore.486980_IWEC_60min.wea' # in order to change the weather file input the 60min .wea dir, do the conversion from epw to wea using execute_epw2wea(bin_dir, source_file, destination_file)
    short_wea_name = "SGP_Singapore.486980_IWEC_5min.wea" # change the output .wea name respectively 
    weather_data = daysimfunc.write_weather_data(wea_file_dir, 0.2, short_wea_name)
    hea_data.append(weather_data)
    
    #WRITE THE GEOMETRY INFO

    sensor_file_dir = sensor_file_path
    rad_file_dir_list = [ROOT + "/radiancebasefile/overhangschema_mat.rad", 
                         rad_file_path]
    geometry_data = daysimfunc.write_geometry_info(filename, sensor_file_dir, rad_file_dir_list)
    hea_data.append(geometry_data)
    
    #WRITE THE RESULTS INFO
    result_data = daysimfunc.write_result_file(filename)
    hea_data.append(result_data)
    
    return hea_data
#------------------------------------------------------------------------------    
def create_rad_file(rad_data, path, filename):
    rad_file_path = path + filename + ".rad"
    if not os.path.isdir(path):
        os.mkdir(path)
    rad_file = open(rad_file_path,  "w")
    for data in rad_data:
        rad_file.write(data)
    rad_file.close()
    return rad_file_path

def create_rad_sensor_file(rad_data, path, filename):
    sensor_file_path = path + filename + ".pts"
    if not os.path.isdir(path):
        os.mkdir(path)
    rad_file = open(sensor_file_path,  "w")
    for data in rad_data:
        rad_file.write(data)
    rad_file.close()
    return sensor_file_path

#---------------------------------------------------------------------------------
def execute_daysim(hea_data, path, filename, bin_dir ):
    #create hea file           
    hea_file_path = path + filename + ".hea"
    if not os.path.isdir(path):
        os.mkdir(path)
    hea_file = open(hea_file_path,  "w")
    for data in hea_data:
        hea_file.write(data)
    hea_file.close()
    #within the folder create 5 folder :pts rad res tmp wea 
    sub_hea_folders = ["pts", "rad", "res","tmp", "wea"]
    for folder in range(len(sub_hea_folders)):
        sub_hea_folder = sub_hea_folders[folder]
        sub_hea_folders_path = path + sub_hea_folder
        
        if not os.path.isdir(sub_hea_folders_path):
            os.mkdir(sub_hea_folders_path)
        if os.path.isdir(sub_hea_folders_path):
            files_in_dir = os.listdir(sub_hea_folders_path)
            for file in files_in_dir:
                os.remove(sub_hea_folders_path + "/" + file )
    
    bin_dir = bin_dir[:-1]
    os.chdir(bin_dir)
    
    
    command1 =  "./ds_shortterm " +  hea_file_path
    
    os.system(command1)
    command2 = "./radfiles2daysim " +  "'" + hea_file_path +"'" + " -g -m -d"
    os.system(command2)
    command3 = "./gen_dc " +  "'" + hea_file_path +"'"
    os.system(command3)
    command4 = "./ds_illum " +  "'" + hea_file_path +"'" 
    os.system(command4)
    command5 = "./gen_directsunlight " +  "'" + hea_file_path +"'" 
    os.system(command5)
    command6 = "./ds_autonomy " +  "'" + hea_file_path +"'" 
    os.system(command6)
    
#---------------------------------------------------------------------------------
def random_genotype(size):
    genotype = []
    for _ in range(size):
        genotype.append(random.random())
    return genotype
#--------------------------------------------------------------------------------
def map_genotype(genotype):
    # 1st gene is length (width is dependent on lenght due to constant area)
    # 2nd gene is the height
    # 3rd gene is rotation
    # 4th to 7th genes are wall materials (0 to 4) 
    # 8th to 11th genes are shade lengths between 0 and 2
    # 12th gene is roof material 
    # 13th gene is floor material 
    # 14th gene is rf slope 
    building_length = range(8, 29)
    building_heights = [2.5, 3, 3.5, 4, 4.5, 5]
    rotation = range(0,360, 10)
    wall_mat = range(0, 4)
    roof_mat = [0,1]
    flr_mat = [0,1]
    slope = [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1]
    variables = []
    variables.append(gmap(genotype[0] ,  building_length))
    variables.append(gmap(genotype[1] ,  building_heights))
    variables.append(gmap(genotype[2] ,  rotation))
    
    for i in range(3, 7):
        variables.append(gmap(genotype[i], wall_mat))
                         
    for i in range(7, 11):
        variables.append(round ((genotype[i]* 2), 1))
    
    variables.append(gmap(genotype[11] ,  roof_mat))
    variables.append(gmap(genotype[12] ,  flr_mat))
    variables.append(gmap(genotype[13] ,  slope))
    
    return variables
#--------------------------------------------------------------------------------
def process_da_result(path, filename):
    da_results = open(path + "res/" + filename  + ".da", "r")
    da_result_stuff = da_results.readlines()
    
    num_da_list = []
    
    #daysim results processing average the DA
    for line in range(len(da_result_stuff)-2): 
        lines =  da_result_stuff[2+line][78:83] 
        numbers_da = float(lines)
        num_da_list.append(round(numbers_da, 1))
    avg_da = sum(num_da_list) / len(num_da_list)
    avg_da = round(avg_da, 1)
    return avg_da

def process_illum_result(path, filename):
    illum_results = open(path + filename + ".txt", "r")
    illum_res_list = []
    for illum_result in illum_results:
        words  = illum_result.split()
        numbers = map(float, words)
        irradiance = round((0.265 * numbers[0]) + (0.670 * numbers[1]) + (0.065 * numbers[2]), 1)
        illuminance = irradiance * 179
        
        illum_res_list.append(illuminance)
        
    total = sum(illum_res_list) 
    avg = round(total/len(illum_res_list), 1)

    return avg 
    
    
def process_energy_results(path,  filename):
    
    #energyplus results processing average the energytransfer 
    energy_results = open(path + "Output/"  + filename + "Meter.csv", "r")
    energy_list = []
    energy_results.next()
    for energy_result in energy_results:
        words = energy_result.split (",")
        numbers = map(float, words[1:])
        energy_list.append(numbers)
    total = (sum(energy_list[0]) + sum(energy_list[1])) / 22
    total = total * 2.77777777777778E-07 # convert from J to KWh
    return total
    

def write_results(results):
    result_filepath = os.path.join(ROOT, "overallresult/")
    if not os.path.isdir(result_filepath):
        os.mkdir(result_filepath)
    result_file = open( result_filepath  + "finalresult.csv",  "w")
    #write the results into a csv file 
    result_file.write("project_name,daylight_autonomy(%),total_energy_transfer(kWh)(daily_avg),costfactor\n")
    result_file.write(results)
    result_file.close()

def develop(genotype):
    variables = map_genotype(genotype)
    print variables
    building = Building()
    _ = make_geometry(variables, building)
    rad_file = generate_rad_file(variables, building)
    idf_file = generate_idf_file(variables, building)
    return rad_file,  idf_file, building 
    
def eval_energy(idf_data):
    path = ROOT + "/energyplusbasefile/ep_out/"
    filename  = "results"
    execute_energyplus(idf_data,  path,  filename)
    result = process_energy_results(path,  filename)
    return result
    
def eval_daylight(rad_data):
    path = ROOT + "/daysimbasefile/daysim_out/"
    filename  = "da_results"
    bin_dir = "/home/dexen/daysim/bin/"
    rad_path = ROOT + "/radiancebasefile/rad_out/"
    rad_filename  = "rad_results"
    sensor_path = ROOT + "/radiancebasefile/"
    sensor_filename = "ovrhg_sensor_pt"
    
    sensor = create_rad_sensor_file(rad_data[1], sensor_path, sensor_filename)
    rad = create_rad_file(rad_data[0], rad_path, rad_filename)
    hea_file = generate_hea_file(path, filename, rad, sensor)
    execute_daysim(hea_file, path, filename, bin_dir)
    result = process_da_result(path, filename)
    return result 

def eval_daylight_rad(rad_data):
    
    path = ROOT + "/radiancebasefile/rad_out/"
    filename  = "rad_results"
    sensor_path = ROOT + "/radiancebasefile/"
    sensor_filename = "ovrhg_sensor_pt"
    sensor = create_rad_sensor_file(rad_data[1], sensor_path, sensor_filename)
    rad = create_rad_file(rad_data[0], path, filename)
    execute_radiance(rad, sensor)
    result = process_illum_result(path, filename)
    return result 
    
def setup():
    weather_file = "SGP_Singapore.486980_IWEC"
    source_file =  '/home/dexen/daysim/wea/' + weather_file + '.epw'
    destination_file = '/home/dexen/daysim/wea/' + weather_file + '_60min.wea'
    bin_dir = "/home/dexen/daysim/bin"
    daysimfunc.execute_epw2wea(bin_dir, source_file, destination_file)

#--------------------------------------------------------------------------------
# MAIN SCRIPT
#--------------------------------------------------------------------------------
random.seed()
#CONVERT EPW TO WEA
setup()

num_of_design = 1
results = ""
for counter in range(num_of_design):
    #generate the variables for the developmental script
    genotype = random_genotype(14)
    #developmental script
    rad_idf_data = develop(genotype)
    #evaluation
    daylight = eval_daylight(rad_idf_data[0])
    energy = eval_energy(rad_idf_data[1])
    cost = str(rad_idf_data[2].costfactor[0])
    results = results + str(counter) + ","+ str(daylight) + "," +  str(energy) + "," +  cost +"\n" 
    print "done"
    
#write the results into a csv file 
write_results(results)
print "FINISH "







